#include "client.h"

int fileContentHash(const char *filePath, char hash[]) {
	// 申请一个数据结构
	SHA_CTX ctx;
	// 初始化
	SHA1_Init(&ctx);
	int fd = open(filePath, O_RDWR);
	char buf[4096];
	while (1) {
		bzero(buf, sizeof(buf));
		ssize_t sret = read(fd, buf, sizeof(buf));
		SHA1_Update(&ctx, buf, sret); //把读到的文件内容更新到ctx
		if (sret == 0) {
			break;
		}
	}
	// Final
	unsigned char md[20]; //保存2进制的哈希值
	SHA1_Final(md, &ctx);
	char sha1str[41] = {0};//保存一个字符串，内容是16进制数
	for (int i = 0; i < 20; ++i) {
		char temp[3] = {0}; // 8bit二进制 --> 2位16进制
		sprintf(temp, "%02x", md[i]);
		strcat(sha1str, temp); //拼接到结果中
	}
	strncpy(hash, sha1str, 40);
	hash[40] = '\0';
	return 0;
}


int gets_client(int sockfd, char *filename) {
	tlvPacket_t packet;
	memset(&packet, 0, sizeof(packet));

	// 1.发送文件名
	packet.type = GETS;
	packet.length = strlen(filename);
	memcpy(packet.value, filename, packet.length);
	send(sockfd, (char *)&packet, sizeof(packet.type) + sizeof(packet.length) + packet.length, MSG_NOSIGNAL);

	// 2.接收文件是否存在的错误信息(不太确定后续需要单独测试)
	int error_flag;
	recv(sockfd, &error_flag, sizeof(error_flag), MSG_WAITALL);
	if (error_flag == 0) { // 服务器返回错误
		printf("%s\n", "filename error, please input again!");
		return -1;
	}

	// 打开/创建文件
	umask(0);
	int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);

	// 接受文件大小
	off_t filesize;
	memset(&packet, 0, sizeof(packet));
	recv(sockfd, (char *)&packet.type, sizeof(packet.type), MSG_WAITALL);
	recv(sockfd, (char *)&packet.length, sizeof(packet.length), MSG_WAITALL);
	recv(sockfd, packet.value, packet.length, MSG_WAITALL);
	filesize = *((int*)packet.value);

	// 若文件大于100M, 用mmap
	if (filesize > 104857600) {
		ftruncate(fd, filesize);
		char *p = (char *)mmap(NULL, filesize, PROT_WRITE, MAP_SHARED, fd, 0);
		recv(sockfd, p, filesize, MSG_WAITALL);
		munmap(p, filesize);
	} else {
		while (1) {
			memset(&packet, 0, sizeof(packet));
			recv(sockfd, (char *)&packet.type, sizeof(packet.type), MSG_WAITALL);
			recv(sockfd, (char *)&packet.length, sizeof(packet.length), MSG_WAITALL);
			if (packet.length > 0) {
				recv(sockfd, packet.value, packet.length, MSG_WAITALL);
				write(fd, packet.value, packet.length);
			} else {
				break;
			}
		}
	}
	close(fd);
	//printf("recv complete\n");
	return 0;
}

int puts_client(int sockfd, char *filename) {
	tlvPacket_t packet;
	int ifExist = 1; // 文件是否存在

	//判断文件名错误的处理
	if (access(filename, F_OK) != 0) {
		printf("filename error, please input again!\n");
		ifExist = -1;
		send(sockfd, &ifExist, sizeof(ifExist), MSG_NOSIGNAL);
		return -1;
	}
	send(sockfd, &ifExist, sizeof(ifExist), MSG_NOSIGNAL);

	// 计算文件哈希值
	char hash[41] = {0};
	fileContentHash(filename, hash);
	// printf("hash = %s\n", hash);
	// printf("strhash = %ld\n", strlen(hash));

	// 将文件哈希发送给服务端
	//send(sockfd, hash, sizeof(hash), MSG_NOSIGNAL);
	// 用tlv发送
	memset(&packet, 0, sizeof(packet));
	packet.type = PUTS;
	packet.length = strlen(hash);
	memcpy(packet.value, hash, packet.length);
	send(sockfd, &packet, sizeof(packet.type) + sizeof(packet.length) + packet.length, MSG_NOSIGNAL);

	memset(&packet, 0, sizeof(packet));
	// 发送文件名
	packet.type = PUTS;
	packet.length = strlen(filename);
	memcpy(packet.value, filename, packet.length);
	send(sockfd, &packet, sizeof(packet.type) + sizeof(packet.length) + packet.length, MSG_NOSIGNAL);

	// 是否秒传？
	int transFlag;
	recv(sockfd, &transFlag, sizeof(transFlag), MSG_WAITALL);

	if (transFlag == 0) {
		// 可读打开上传文件
		int fd = open(filename, O_RDONLY);

		// 获取上传文件大小
		struct stat statbuf;
		fstat(fd, &statbuf);
		off_t filesize = statbuf.st_size;
		//printf("filesize = %lld\n", (long long)filesize);

		// 发送文件大小
		memset(&packet, 0, sizeof(packet));
		packet.type = PUTS;
		packet.length = sizeof(filesize);
		memcpy(packet.value, &filesize, packet.length);
		//memmove(packet.value, &filesize, packet.length);
		send(sockfd, (char *)&packet, sizeof(packet.type) + sizeof(packet.length) + packet.length, MSG_NOSIGNAL);

		// 若传输文件大于100M, 采用mmap
		if (filesize > 104857600) {
			char *p = (char *)mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
			send(sockfd, p, filesize, MSG_NOSIGNAL);
			munmap(p, filesize);
		} else {
			while (1) {
				memset(&packet, 0, sizeof(packet));
				packet.type = PUTS;
				packet.length = read(fd, packet.value, sizeof(packet.value));
				if (packet.length > 0) {
					send(sockfd, (char *)&packet, sizeof(packet.type) + sizeof(packet.length) + packet.length, MSG_NOSIGNAL);
				} else {
					break;
				}
			}

			// 发送结束标志
			memset(&packet, 0, sizeof(packet));
			packet.type = PUTS;
			send(sockfd, (char *)&packet, sizeof(packet.type) + sizeof(packet.length) + packet.length, MSG_NOSIGNAL);
		}
		close(fd);

	} else if (transFlag == 2) {
		printf("File already exists.\n");
		return 0;
	}
	//printf("send complete\n");
	return 0;
}
